
#include "SimpleMap.h"
#include "Element.h"
#include "MazeGenerator.h"
#include <fstream>
namespace Core
{
	namespace GameLogic
	{
		// initialize map by MazeGenerator
		SimpleMap::SimpleMap(int mapWidth, int mapHeight, int blockWidth,int blockHeight)
			:m_Width(mapWidth),
			 m_Height(mapHeight),
			 m_BlockWidth(blockWidth),
			 m_BlockHeight(blockHeight)
		{
			unsigned short data;
			m_MapInfo.resize(m_Width*m_Height);
			int* tmap=new int[m_Width*m_Height];
			Util::MazeGenerator::GetMaze(tmap,m_Width,m_Height,(int)(Base::MapInfo::BLOCK),(int)(Base::MapInfo::PASS));
			for(int i=0;i<m_Height;i++)
				for(int j=0;j<m_Width;j++)
				{
					
					data=tmap[i*m_Width+j];
					if(data!=(int)(Base::MapInfo::BLOCK) && data!=(int)(Base::MapInfo::PASS) )
						throw std::exception("Not a proper data");
					MapInfo info((MapInfo::Info)data);
					m_MapInfo[i*m_Width+j]=info;

				}
			
			delete tmap;
			mLogicMap.Init(this);
		}

		// initialize map from file
		SimpleMap::SimpleMap(const std::string& filename,int blockWidth,int blockHeight)
			:m_BlockWidth(blockWidth),m_BlockHeight(blockHeight)
		{
			std::ifstream in;
			try{
				in.open(filename.c_str());
			}
			catch(...)
			{
				string p="No such a file ";
				p+=filename;
				throw std::exception(p.c_str());
			}
			unsigned short data;

			in>>m_Width;
			in>>m_Height;
			
			m_MapInfo.resize(m_Width*m_Height);
			for(int i=0;i<m_Height;i++)
			{
				for(int j=0;j<m_Width;j++)
				{
					
					in>>data;
					if(data!=(int)(Base::MapInfo::BLOCK) && data!=(int)(Base::MapInfo::PASS) )
						throw std::exception("Not a proper data");
					MapInfo info((MapInfo::Info)data);
					m_MapInfo[i*m_Width+j]=info;

				}
			}
			in.close();
			mLogicMap.Init(this);
		}
		Size SimpleMap::GetBlockSize() 
		{
			return Size(m_BlockWidth,m_BlockHeight);
		}
		Size SimpleMap::GetMapSize()
		{
			return Size(m_Width*m_BlockWidth,m_Height*m_BlockHeight);
		}
		Size SimpleMap::GetMapSizeByBlock()
		{
			return Size(m_Width,m_Height);
		}
		Position SimpleMap::BlockPosition(const Position& p)
		{
			return Position(p.x / m_BlockWidth,p.y / m_BlockHeight);
		}
		Position SimpleMap::GetGridPosition(const Position& p)
		{
			return Position(p.x / m_BlockWidth * m_BlockWidth,p.y / m_BlockHeight * m_BlockHeight);
		}
		SimpleMap::MapInfo SimpleMap::GetInfo(const Position& p)
		{
			Position& t=BlockPosition(p);
			return m_MapInfo[t.y*m_Width+t.x];
		}
		void SimpleMap::AddElement(Element* element)
		{
			assert(element);
			Position& t=this->BlockPosition (element->GetPosition());
			m_MapInfo[t.y*m_Width+t.x].elements[element]=Core::Null();
		}
		void SimpleMap::RemoveElement(Element* element)
		{
			assert(element);
			Position& t=this->BlockPosition (element->GetPosition());
			m_MapInfo[t.y*m_Width+t.x].elements.erase(element);
		}
	
		void SimpleMap::OnMove(SourceType& source)
		{
			Position& pre=BlockPosition(source.GetPrePosition());
			Position& t=BlockPosition(source.GetPosition());
			if(pre==t) return;
			assert(m_MapInfo[pre.y*m_Width+pre.x].elements.find(&source)!=m_MapInfo[pre.y*m_Width+pre.x].elements.end());
			m_MapInfo[pre.y*m_Width+pre.x].elements.erase(&source);
			m_MapInfo[t.y*m_Width+t.x].elements[&source]=Null();
		}
		Position SimpleMap::GetGridPositionFromBlockPosition (const Core::Position &p)
		{
			return Position(p.x*m_BlockWidth,p.y*m_BlockHeight);
		}
		SimpleMap::LogicMap& SimpleMap::GetLogicMap()
		{
			return mLogicMap;
		}

		SimpleMap::LogicMap::LogicMap() 
		{}
		void SimpleMap::LogicMap::Init(SimpleMap* map)
		{
			mMap=map;
		}
		Size SimpleMap::LogicMap::GetMapSize()
		{
			return mMap->GetMapSizeByBlock();
		}
		void SimpleMap::LogicMap::AddElement(Element* element)
		{
			mMap->AddElement(element);
		}
		void SimpleMap::LogicMap::RemoveElement(Element* element)
		{
			mMap->RemoveElement(element);
		}
		SimpleMap::MapInfo SimpleMap::LogicMap::GetInfo(const Position&p)
		{
			return mMap->m_MapInfo[p.y*mMap->m_Width+p.x];
		}
		SimpleMap::LogicMap::LogicPart& SimpleMap::LogicMap::GetLogicMap()
		{
			return *this;
		}
	}
}